package site.param.init;

import com.sun.corba.se.impl.io.ObjectStreamClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import site.param.annotation.ParameterManager;

import java.io.NotSerializableException;
import java.lang.reflect.Field;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2016/12/27.
 */
public class ParameterInterpret {
    private static Logger logger = LoggerFactory.getLogger(ParameterInterpret.class);
    public static Map<String,Class> initClassMap(String scanPackage){
        if (scanPackage==null||"".equals(scanPackage))
        logger.error("this  ParameterInitFactory error ,scanPackage  not null");
        Map<String,Class> hashTable=new Hashtable<String,Class>();
        List<Class> classes= ParameterUtil.getClassByPackage(scanPackage,false);
        for (Class clazz: classes){
            hashTable.put(ObjectStreamClass.getSerialVersionUID(clazz)+"",clazz);
        }
        return hashTable;
    }

    public static  Map<String,ParameterMap>  interpret(Map<String,Class> classes){
        Map<String,ParameterMap> parameterMap=new Hashtable<String, ParameterMap>();
        for (String ckey: classes.keySet()){
            try {
                parameterMap.put(interpretClass(classes.get(ckey)).getSerialUID(),interpretClass(classes.get(ckey)));
            } catch (Exception e) {
                logger.error("this interpret ckey:{},error:{}",ckey,e.getMessage());
                continue;
            }
        }
        return parameterMap;
    }

    private static ParameterMap interpretClass(Class clazz) throws Exception{
        ParameterMap parameterMap=classDesc(clazz);
        ParameterType parameterType=null;
        Map<String,ParameterType> parameterTypes=new Hashtable<String, ParameterType>();
        Field[] fields=clazz.getFields();
        Object obj= clazz.newInstance();
        if (fields!=null){
            for (Field field:fields){
                parameterType=new ParameterType();
                parameterType.setFiledName(field.getName());
                parameterType.setFiledType(field.getType());
                parameterType.setFiledValue(field.get(obj)+"");
                parameterTypes.put(field.getName(),parameterType);
            }
        }
        parameterMap.setParameterTypes(parameterTypes);
        return parameterMap;
    }
    private static ParameterMap classDesc(Class clazz) throws NotSerializableException {
        ParameterMap parameterMap=new ParameterMap();
        ParameterManager annotation=(ParameterManager) clazz.getAnnotation(ParameterManager.class);
        if (ObjectStreamClass.getSerialVersionUID(clazz)==0||ObjectStreamClass.getSerialVersionUID(clazz)==-1){
            logger.error("class notSerializable or serialVersionUID =-1 :  {} , init fail  ",clazz.getName());
            throw new NotSerializableException();
        }
        parameterMap.setSerialUID(ObjectStreamClass.getSerialVersionUID(clazz)+"");
        String parameterDesc=annotation.parameterDesc();
        if("".equals(parameterDesc)){
            parameterDesc= "default desc";
        }
        parameterMap.setParameterDesc(parameterDesc);
        parameterMap.setName(clazz.getSimpleName());
        parameterMap.setPackageName(clazz.getPackage().getName());
        return parameterMap;
    }
    public static void setParamter(Class clazz,ParameterMap parameterMap) throws  Exception{
        Field[] fields=clazz.getFields();
        Object object=clazz.newInstance();
        for (Field field:fields) {
            try {
                switch (field.getType().getName()){
                     case "java.lang.String":
                         field.set(object,String.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Long":
                         field.set(object,Long.parseLong(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Integer":
                         field.set(object,Integer.parseInt(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Double":
                         field.set(object,Double.parseDouble (parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Float":
                         field.set(object,Float.parseFloat (parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Short":
                         field.set(object,Short.parseShort (parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Boolean":
                         field.set(object,Boolean.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "java.lang.Byte":
                         field.set(object,Byte.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()));
                        break;

                     case "int":
                         field.set(object,Integer.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).intValue());
                        break;

                     case "long":
                         field.set(object,Long.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).longValue());
                        break;

                     case "char":
                         field.set(object,(parameterMap.getParameterTypes().get(field.getName()).getFiledValue().charAt(0)));
                        break;

                     case "short":
                         field.set(object,Short.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).shortValue());
                        break;

                     case "double":
                        field.set(object,Double.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).doubleValue());
                        break;

                     case "float":
                         field.set(object,Float.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).floatValue());
                        break;

                     case "byte":
                         field.set(object,Byte.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).byteValue());
                        break;

                     case "boolean":
                         field.set(object,Boolean.valueOf(parameterMap.getParameterTypes().get(field.getName()).getFiledValue()).booleanValue());
                        break;

                    default:
                        break;
                }
            } catch (IllegalArgumentException |IllegalAccessException e) {
                logger.error("field set value error ,filed:{},value()",field.getType().getName(),parameterMap.getParameterTypes().get(field.getName()).getFiledValue());
                continue;
            }


        }

    }

}
